import bs4
import scrapy
from ..items import QcwyItem
from selenium import webdriver
import time
from loguru import logger
from selenium.webdriver.chrome.service import Service
import os
from selenium.webdriver.common.by import By

# 定义一个名为QcwySpider的Scrapy爬虫类
class QcwySpider(scrapy.Spider):
    name = "qcwy_spider"
    allowed_domains = ['mkt.51job.com']# 设置爬虫被允许爬取的域名列表

    # key_word = 'python'  查询关键字，通过启动线程，由tkinter页面传过来
    # 初始窗口直接指定为登录页面
    # start_urls = ['https://passport.jd.com/new/login.aspx']
    # 重写start_requests方法，自定义启动爬虫时，执行的操作
    def start_requests(self):
        # 登录页面
        login_url = 'https://mkt.51job.com/tg/sem/LP_2023_CB1.html?from=bingpz&partner=SEM_pcbingpz_02'
        # 如果网站不需要登录，注释掉登录这一步，同样在tkinter页面也就不需要确认登录状态了
        # 如需修改一定要理清该处运行逻辑
        self.login(login_url)
        yield scrapy.Request(
            # 指定首次请求打开的页面，这里是51job的搜索页面
            url='https://we.51job.com/pc/search',
            callback=self.parse,  # 当这个请求完成后，会调用parse方法处理响应
        )

    # params 为tkinter传递过来的参数，类型为list
    # pipe为线程通信的管道，为tkinter和scrapy提供交互信息通道
    def __init__(self, params, pipe):
        # 将chromedirer直接集成在项目目录下
        current_path = os.getcwd() # 获取当前工作目录，用于定位chromedriver的路径
        service = Service(executable_path=current_path + '/chromedriver/chromedriver.exe')
        options = webdriver.ChromeOptions() # 创建Chrome浏览器选项
        self.driver = webdriver.Chrome(service=service, options=options)  # 初始化Chrome浏览器实例，并保存为self.driver
        self.params = params  # 保存tkinter传递过来的参数
        self.key_word = params[0]   # 第一个元素是查询关键字
        self.page_amount = params[1]  # params的第二个元素是要爬取的页面数量
        self.pipe = pipe  # 保存线程通信的管道对象
        # 通过线程管道向tkinter窗口发消息
        pipe.send("前程无忧招聘信息 scrapy 对象已创建")

    def login(self, url):
        self.driver.maximize_window() # 最大化浏览器窗口
        self.driver.get(url) # 通过WebDriver向指定URL发送GET请求，模拟浏览器打开该页面
        logger.info('等待登录状态确认....')  # 记录日志信息，表示正在等待登录状态确认
        while True:
            time.sleep(5)  # 等待5秒
            # 检查线程管道是否有消息未读取 pipe是一个线程通信的管道，用于tkinter和Scrapy之间交互信息
            if self.pipe.poll():
                # 读取管道信息
                login_check = self.pipe.recv()
                # 如果读取到的消息是'login'，则表示登录状态已确认
                if login_check == 'login':
                    break # 跳出无限循环
        logger.info('已确认登录状态，爬虫继续执行....')
        self.pipe.send("scrapy 接收到登录确认信息，准备开始爬虫")

    def parse(self, response):
        time.sleep(2)  # 等待时间
        # 构造目标URL，将关键字和页面参数拼接进去
        self.driver.get('https://we.51job.com/pc/search?keyword=' +
                        self.key_word)
        # 爬取的页数和关键字均有tkinter窗口传递过来
        # 开始遍历需要爬取的页数
        for i in range(self.page_amount):
            time.sleep(3)  # 操作等待时间
            # 通过管道发送给tkinter爬虫进度信息
            self.pipe.send("scrapy 爬取第 " + str(i + 1) + " 页...")

            # 获取当前页面的HTML源码
            html = self.driver.page_source
            # 使用BeautifulSoup解析HTML
            soup = bs4.BeautifulSoup(html, 'html.parser')
            # 查找包含职位列表的div元素
            ul_element = soup.find('div', {'class': 'joblist'})
            # 在ul元素中查找所有的职位项（li元素）
            li_elements = ul_element.find_all('div', {'class': 'joblist-item'})
            # 遍历每个职位项
            for li_item in li_elements:
                item = QcwyItem()   # 创建一个新的Item对象用于存储职位信息
                # 查找职位名称和链接的div元素
                name_link_div = li_item.find('div', {'class': 'joblist-item-top'})
                # 提取职位名称
                item['name'] = name_link_div.find('span').text
                # 提取职位薪资
                item['price'] = name_link_div.find('span', {'class': 'sal shrink-0'}).text
                # 查找标签的div元素
                tags_all = li_item.find('div', {'class': 'tags'})
                if tags_all:
                    div_elements = tags_all.find_all('div', {'class': 'tag'})
                    tag_texts = [div.text for div in div_elements]  # 获取所有div元素的文本内容
                    item['tags'] = '、'.join(tag_texts)  # 用逗号连接所有文本内容 shrink-0
                else:
                    item['tags'] = '无'
                # 提取公司名称
                item['cname'] = li_item.find('a', {'class': 'cname text-cut'}).text
                # 查找公司第一地址
                cd1_element = li_item.find('span', {'class': 'dc text-cut'})
                if cd1_element:
                    item['cd1'] = cd1_element.text
                else:
                    item['cd1'] = '无'

                # 提取公司第二地址（区域或详细地址）
                item['cd2'] = li_item.find('span', {'class': 'dc shrink-0'}).text
                # 提取职位基础信息
                item['base'] = li_item.find('div', {'class': 'shrink-0'}).text

                # 设置关键字和来源
                item['key_word'] = self.key_word
                item['sales'] = '前程无忧'

                # 输出查看
                print("name:", item['name'])
                print("price:", item['price'])
                print("tags:", item['tags'])
                print("cname:", item['cname'])
                print("cd1:", item['cd1'])
                print("cd2:", item['cd2'])
                print("base:", item['base'])
                print("key_word:", item['key_word'])
                print("sales:", item['sales'])
                print('------------')  # 打印一个分隔符，以便于区分不同的item
                yield item
